package com.bootdo.collection.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.bootdo.collection.dao.PictureDao;
import com.bootdo.collection.domain.*;
import com.bootdo.collection.service.PictureService;
import com.bootdo.collection.service.PictureSetService;
import com.bootdo.collection.service.PushStationService;
import com.bootdo.collection.service.SourceStationService;
import com.bootdo.collection.utils.*;
import com.bootdo.common.utils.R;
import com.bootdo.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;

@Service
public class PictureServiceImpl implements PictureService {
    @Autowired
    PictureDao pictureMapper;
    @Autowired
    PictureSetService pictureSetService;
    @Autowired
    SourceStationService sourceStationService;
    @Autowired
    PushStationService pushStationService;
    @Autowired
    ChangeImageSizeUtil changeImageSizeUtil;
    @Autowired
    private RecursionUtil recursionUtil;
    private static boolean PICTURE_SET = true;
    private LinkedBlockingQueue blockingQueue = new LinkedBlockingQueue();
    private ThreadPoolExecutor executor = new ThreadPoolExecutor(10,30,5, TimeUnit.SECONDS,blockingQueue);
    @Override
    public List<PictureDO> getPicturesBySetId(int pictureSetId,int stationId) {
        List<PictureDO> list = pictureMapper.getPicturesBySetId(pictureSetId);
        SourceStationDO sourceStationDO = sourceStationService.get(stationId);
        sourceStationDO = recursionUtil.recursion(sourceStationDO);
        //根据条件判断是否下载图片
        if(sourceStationDO.getIsDownload() == 1){
            List<Future> futureList = new ArrayList<>();
            //多线程下载图片
            for(PictureDO picture:list){
                futureList.add(executor.submit(new ReplacePicUrlToBase64Util(picture,sourceStationDO.getRefer())));
            }
            //如果图片没下载完成，阻塞主线程
            for(Future future:futureList){
                try {
                    future.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
//            PicJsonDO picJsonDO = new PicJsonDO();
//            picJsonDO.setPictureSetId(list.get(0).getPictureSetId());
//            picJsonDO.setRefer(sourceStationDO.getRefer());
//            picJsonDO.setPictureDOS(list);
//            JedisUtil.init();
//            //设置了防止重复添加的队列
//            String exist = JedisUtil.hget(pictureSetId,"field1");
//            if(exist == null){
//               //将下载的图集id加入哈希表，用于判断是否此图集是否已下载过
//                JedisUtil.hset(pictureSetId,"field1",pictureSetId);
//               //加入一个队列,客户端会通过接口不断从这个队列请求数据
//                JedisUtil.lpush("picJsonDO",picJsonDO.toString());
//            }
//            List<PictureDO> pictureDOS = null;
//            String picJsonPlus;
//            //客户端会将图片上传到该队列中,如果客户端已经上传到该队列，则返回数据，否则返回空
//            picJsonPlus = JedisUtil.hget(String.valueOf(list.get(0).getPictureSetId()),"field2");
//            if(picJsonPlus != null){
//                PicJsonDO piJsonDOP = JSONObject.parseObject(picJsonPlus,PicJsonDO.class);
//                pictureDOS = piJsonDOP.getPictureDOS();
//                for(PictureDO pictureDO: pictureDOS){
//                    pictureDO.setPictureUrl("data:image/jpg;base64,"+pictureDO.getPictureUrl());
//                }
//            }
//            list = null;
//            picJsonDO = null;
//            picJsonPlus = null;
//            return pictureDOS;
        }
        return list;
    }

    @Override
    public R deleteByPictureId(int pictureId) {
        int count = pictureMapper.deleteByPictureId(pictureId);
        if(count > 0){
            return R.ok();
        }
        return R.error();
}

    /**
     * 上传图片到ftp,同时将需要的数据传到对应的后台
     * @param pictureSetId  图集id
     */
    @Override
    public void upload(int pictureSetId,String title,int[] station,int[] pictureIds) throws Exception {
        //map是经过裁剪的不同站点的各自尺寸的图集,键是要上传的站点id,值是图片字节流
        List<Map<Integer,InputStream>> picturesStream = new ArrayList<>();
        List<byte[]> pictureDOBytes = new ArrayList<>();
        //根据图片id查找图片
        List<PictureDO> pictureDOList = pictureMapper.getPicturesByIds(pictureIds);
        //本地下载图片
        for(PictureDO pictureDO:pictureDOList){
            PictureSetDO pictureSetDO = pictureSetService.getPictureSetDOById(pictureDO.getPictureSetId());
            SourceStationDO sourceStationDO = sourceStationService.get(pictureSetDO.getSourceStationId());
            byte[] bytes = ImageByteUtil.fetchContent(pictureDO,sourceStationDO.getRefer());
            if(bytes != null){
                pictureDOBytes.add(bytes);
            }
        }
        try{
            //这部分注释的代码是从爬虫客户端下载图片的处理,现在是由后台下载图片
//             如果没缓存资源，推送时都从客户端下载图片，后传回redis
//            if(pictureDOBytes == null){
//                List<PictureDO> pictureDOS = pictureMapper.getPicturesByIds(pictureIds);
//                JedisUtil.init();
//                PicJsonDO picJsonDO = new PicJsonDO();
//                picJsonDO.setRefer(sourceStationDO.getRefer());
//                picJsonDO.setPictureSetId(pictureSetId);
//                picJsonDO.setPictureDOS(pictureDOS);
//                JedisUtil.lpush("picJsonDO",picJsonDO.toString());
//                //从redis取60次，即单套图最长上传时间为10分钟
//                for(int count = 0;count < 60 && pictureDOBytes == null;count++){
//                    pictureDOBytes = getFromRedis(pictureSetId,pictureIds);
//                    //休眠10秒
//                    try {
//                        Thread.sleep(10000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//                //如果这时还是为空，抛出异常，记录问题
//                if(pictureDOBytes == null){
//                    throw new Exception("无法从redis中获取资源,推送失败,可能是客户端无法下载");
//                }
//            }
            if(pictureDOBytes.size() == 0){
                throw new Exception("图片集合为空,无法下载图片");
            }
            for(byte[] pictureByte: pictureDOBytes){
                try {
                    picturesStream.add(changeImageSizeUtil.getChangeImageInput(station,pictureByte));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            PictureSetDO pictureSetDO = pictureSetService.getPictureSetDOById(pictureSetId);
            pictureSetDO.setCount(pictureSetDO.getCount() + 1);
            //更新使用次数
            pictureSetService.updateCount(pictureSetDO);
            //上传多个站点
            PushStationDO pushStationDO;
            List<String> imageList;
            StringBuilder stringBuilder = new StringBuilder();
            for(int id: station){
                pushStationDO = pushStationService.get(id);
                //组装上传网站名称,多个站点用&分割
                stringBuilder.append("&" + pushStationDO.getPushStationName());
                //内容图上传ftp
                R r = UploadFtpUtil.upload(picturesStream, pushStationDO,PICTURE_SET);
                //获得图片集合
                imageList = (ArrayList)r.get("imageList");
//                获得路径
                String path = (String)r.get("path");
//                上传网站
                UploadStationUtil.upload(path,title,imageList,pushStationDO.getPushStationUrl());
            }
            //删除第一个&标记符
            stringBuilder.deleteCharAt(0);
            //更新上传网站字段
            pictureSetService.updateUploadStationName(stringBuilder.toString(),pictureSetId);
        }finally {
            //释放资源
            try {
                for (Map<Integer, InputStream> picMap : picturesStream) {
                    for (Map.Entry<Integer, InputStream> entry : picMap.entrySet()) {
                        entry.getValue().close();
                    }
                }
                //让gc快点回收
                picturesStream = null;
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 添加图集到伪原创库
     * @param pictureSetDO 添加到伪原创库的图集
     */
    @Override
    public void addLibrary(PictureSetDO pictureSetDO) {
        JedisUtil.init();
        //1.根据pictureSetId，查询出对应的图集.
        List<PictureDO> pictureDOS = pictureMapper.getPicturesBySetId(pictureSetDO.getPictureSetId());
        SourceStationDO sourceStationDO = sourceStationService.get(pictureSetDO.getSourceStationId());
        //2.根据sourceStationId,判断是否需要下载
        if(sourceStationDO.getIsDownload() == 1){
            for(PictureDO pictureDO:pictureDOS){
              ReplacePicUrlToBase64Util.serialReplaceUrl(pictureDO,sourceStationDO.getRefer());
            }
        }
        //3.从伪原创库中取出数据，防止覆盖
        String pictureDOJson = JedisUtil.get(pictureSetDO.getTitle());
        if(StringUtils.isNotBlank(pictureDOJson)){
            List<PictureDO> oldPictureDOS = JSONArray.parseArray(pictureDOJson,PictureDO.class);
            //防止点击同一套图重复添加的情况
            if(!oldPictureDOS.contains(pictureDOS.get(0))){
                oldPictureDOS.addAll(pictureDOS);
            }
            //4.将关键词作为键,集合作为值存入redis，作为伪原创库
            JedisUtil.set(pictureSetDO.getTitle(),oldPictureDOS.toString());
        }else {
            //5.将关键词作为键,集合作为值存入redis，作为伪原创库
            JedisUtil.set(pictureSetDO.getTitle(),pictureDOS.toString());
        }
    }


    /**
     * 从伪原创库中添加图片到图集
     * @param pictureSetId 图集id
     * @param ids 选定的图片
     * @param keyTitle 作为缓存中的存的键,作为伪原创的标识
     * @return
     */
    @Override
    public List<PictureDO> addAtlas(int pictureSetId, int[] ids, String keyTitle) {
        //1.获得原来图集，然后去缓存中找出数组对应的图，加入旧的图集中
        List<PictureDO> pictureDOS = new ArrayList();
        JedisUtil.init();
        String pictureJson = JedisUtil.get(keyTitle);
        if(StringUtils.isNotBlank(pictureJson)){
           List<PictureDO> pictureDOList = JSONArray.parseArray(pictureJson,PictureDO.class);
           HashSet<Integer> set = new HashSet();
           for(int pictureId:ids){
               Iterator<PictureDO> iterator = pictureDOList.iterator();
               while (iterator.hasNext()){
                   PictureDO pictureDO = iterator.next();
                   if(pictureDO.getPictureId() == pictureId){
                       //2.图集中新增图片
                       pictureDOS.add(pictureDO);
                       //3.删除伪原创库中该张图片
                       iterator.remove();
                       //4.将图片所属的图集找出，可能存在多张同属一套图，通过set集合去重
                       set.add(pictureDO.getPictureSetId());
                       break;
                   }
               }
           }
           //5.使用了图集中的其中一张或多张，都将该图集的使用次数加1
           if(set.size() != 0){
               for(Integer id:set){
                  PictureSetDO pictureSetDO = pictureSetService.getPictureSetDOById(id);
                  pictureSetDO.setCount(pictureSetDO.getCount() +1);
                  pictureSetService.updateCount(pictureSetDO);
               }
           }
            //6.将缓存中的数据更新
            JedisUtil.set(keyTitle,pictureDOList.toString());
        }
        //7.将新的图集返回
        return pictureDOS;
    }

    /**
     * 删除伪原创库中的图片
     * @param keyTitle 原创库键
     * @param ids 要删除的图片id
     */
    @Override
    public void deleteFromLibrary(String keyTitle, int[] ids) {
        JedisUtil.init();
        String pictureJson = JedisUtil.get(keyTitle);
        if(StringUtils.isNotBlank(pictureJson)){
            List<PictureDO> pictureDOS =  JSONArray.parseArray(pictureJson,PictureDO.class);
            Iterator<PictureDO> it = pictureDOS.iterator();
            while (it.hasNext()){
                PictureDO pictureDO = it.next();
                for(int id:ids){
                    if(id == pictureDO.getPictureId()){
                        it.remove();
                        break;
                    }
                }
            }
            JedisUtil.set(keyTitle,pictureDOS.toString());
        }
    }

    /**
     *从redis缓存中取出base64,现在没有从客户端下载图片,所以该方法就注释了。
     * @param pictureSetId
     * @param pictureIds
     * @return
     */
//    private List<byte[]> getFromRedis(int pictureSetId,int[] pictureIds){
//         JedisUtil.init();
//         String picJson = JedisUtil.hget(String.valueOf(pictureSetId),"field2");
//         if(picJson == null){
//             return  null;
//         }
//         PicJsonDO picJsonDO = JSONObject.parseObject(picJson,PicJsonDO.class);
//         List<PictureDO> pictureDOS = picJsonDO.getPictureDOS();
//         List<byte[]> pictureDOBytes = new ArrayList<>();
//         Base64.Decoder decoder = Base64.getDecoder();
//         for(PictureDO pictureDO : pictureDOS){
//             for(int pictureId:pictureIds){
//                 if(pictureDO.getPictureId() == pictureId){
//                     String imgBase64 = pictureDO.getPictureUrl();
//                     pictureDOBytes.add(decoder.decode(imgBase64));
//                     break;
//                 }
//             }
//         }
//         return pictureDOBytes;
//    }
}
